package cn.demoncat.util.lang.entity;

import cn.demoncat.util.lang.*;
import cn.demoncat.util.lang.constant.SystemConstant;
import cn.demoncat.util.web.IpUtil;
import lombok.Data;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 系统信息
 *
 * @author 延晓磊
 * @since 2022年06月23日
 */
@Data
public class SystemInfo {

    private static SystemInfo instance;
    private Cpu cpu;
    private Mem mem;
    private Jvm jvm;
    private Sys sys;
    private List<File> files;

    /**
     * 获取系统信息
     *
     * @return
     */
    public static SystemInfo getInstance(){
        if (instance == null) {
            return initInstance();
        }
        return instance;
    }

    /**
     * 构建系统信息
     *
     * @return
     *
     * @author 延晓磊
     * @since 2022年06月23日
     */
    private static synchronized SystemInfo initInstance(){
        if (instance == null) {
            // 系统信息
            SystemInfo info = new SystemInfo();
            oshi.SystemInfo system = new oshi.SystemInfo();
            // 硬件
            HardwareAbstractionLayer hardware = system.getHardware();
            // 异步执行
            CompletableFutureUtil.async(
                    () ->{
                        // CPU
                        info.cpu = new Cpu();
                        CentralProcessor processor = hardware.getProcessor();
                        long[] prevTicks = processor.getSystemCpuLoadTicks();
                        ThreadUtil.sleep(1);
                        long[] ticks = processor.getSystemCpuLoadTicks();
                        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
                        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
                        long softIrq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
                        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
                        long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
                        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
                        long ioWait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
                        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
                        long total = user + nice + sys + idle + ioWait + irq + softIrq + steal;
                        info.cpu.num = processor.getLogicalProcessorCount();
                        info.cpu.sys = DecimalUtil.toPercent(sys, total, 2).doubleValue();
                        info.cpu.used = DecimalUtil.toPercent(user, total, 2).doubleValue();
                        info.cpu.wait = DecimalUtil.toPercent(ioWait, total, 2).doubleValue();
                        info.cpu.free = DecimalUtil.toPercent(idle, total, 2).doubleValue();
                        info.cpu.total = DoubleUtil.toFixed(info.cpu.sys + info.cpu.used, 2);
                    },
                    () ->{
                        // Mem
                        info.mem = new Mem();
                        GlobalMemory memory = hardware.getMemory();
                        info.mem.total = memory.getTotal();
                        info.mem.free = memory.getAvailable();
                        info.mem.used = memory.getTotal() - memory.getAvailable();
                        info.mem.usage = DecimalUtil.toPercent(info.mem.used, info.mem.total, 2).doubleValue();
                        // 操作系统
                        OperatingSystem os = system.getOperatingSystem();
                        info.sys = new Sys();
                        info.sys.bootTime = LocalDateUtil.toLocalDateTime(os.getSystemBootTime());
                        info.sys.ip = IpUtil.LOCAL_IP;
                        info.sys.osName = SystemConstant.OS_NAME;
                        info.sys.osType = SystemConstant.OS_TYPE;
                        // 文件系统
                        info.files = new ArrayList<>();
                        File file;
                        FileSystem fs = os.getFileSystem();
                        for (OSFileStore f : fs.getFileStores()) {
                            file = new File();
                            file.free = f.getUsableSpace();
                            file.total = f.getTotalSpace();
                            file.used = file.total - file.free;
                            file.dirName = f.getMount();
                            file.sysTypeName = f.getType();
                            file.typeName = f.getName();
                            file.usage = DecimalUtil.toPercent(file.used, file.total, 2).doubleValue();
                            info.files.add(file);
                        }
                        // JVM
                        info.jvm = new Jvm();
                        info.jvm.home = SystemUtil.getJavaHome();
                        info.jvm.version = SystemUtil.getJavaVersion();
                        info.jvm.bootTime = SystemUtil.getStartTime();
                        info.jvm.total = SystemUtil.getTotalMemory();
                        info.jvm.max = SystemUtil.getMaxMemory();
                        info.jvm.free = SystemUtil.getFreeMemory();
                        info.jvm.used = info.jvm.total - info.jvm.free;
                        info.jvm.usage = DecimalUtil.toPercent(info.jvm.used,  info.jvm.total, 2).doubleValue();
                    }
            );
            instance = info;
        }
        return instance;
    }

    /**
     * CPU
     *
     * @author 延晓磊
     * @since 2022年06月23日
     */
    @Data
    public static class Cpu {

        /**
         * 核心数
         */
        private int num;

        /**
         * 总使用率
         */
        private double total;

        /**
         * 系统使用率
         */
        private double sys;

        /**
         * 用户使用率
         */
        private double used;

        /**
         * 当前等待率
         */
        private double wait;

        /**
         * 当前空闲率
         */
        private double free;
    }

    /**
     * JVM
     *
     * @author 延晓磊
     * @since 2022年06月23日
     */
    @Data
    public static class Jvm {

        /**
         * 当前占用的内存总数
         */
        private long total;

        /**
         * 最大可用内存总数
         */
        private long max;

        /**
         * 空闲内存
         */
        private long free;

        /**
         * 已用
         */
        private long used;

        /**
         * 资源的使用率
         */
        private double usage;

        /**
         * JDK版本
         */
        private String version;

        /**
         * JDK路径
         */
        private String home;

        /**
         * 启动时间
         */
        private LocalDateTime bootTime;
    }

    /**
     * 內存
     *
     * @author 延晓磊
     * @since 2022年06月23日
     */
    @Data
    public static class Mem {

        /**
         * 总量
         */
        private long total;

        /**
         * 剩余
         */
        private long free;

        /**
         * 已用
         */
        private long used;

        /**
         * 使用率
         */
        private double usage;
    }

    /**
     * 系统
     *
     * @author 延晓磊
     * @since 2022年06月23日
     */
    @Data
    public static class Sys {

        /**
         * Ip
         */
        private String ip;

        /**
         * 操作系统
         */
        private String osName;

        /**
         * 操作类型
         */
        private String osType;

        /**
         * 启动时间
         */
        private LocalDateTime bootTime;

    }

    /**
     * 系统文件
     *
     * @author 延晓磊
     * @since 2022年06月23日
     */
    @Data
    public static class File  {
        /**
         * 盘符路径
         */
        private String dirName;

        /**
         * 盘符类型
         */
        private String sysTypeName;

        /**
         * 文件类型
         */
        private String typeName;

        /**
         * 总大小
         */
        private long total;

        /**
         * 剩余大小
         */
        private long free;

        /**
         * 已经使用量
         */
        private long used;

        /**
         * 资源的使用率
         */
        private double usage;
    }

}
